﻿/*
 * Copyright © 2011 Tristan Reeves, treeves@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Linq.Expressions;
using Sprinkles.ExpressionHandlers;

namespace Sprinkles.Secondary
{
    public class CreationDeployment<T>
    {
        private readonly Deployment<T> m_Owner;
        public CreationDeployment(Deployment<T> owner)
        {
            m_Owner = owner;
        }

        //constructor
        public Deployment<T> Constructor()
        {
            return m_Owner;
        }
        public Arguments<A, T> Constructor<A>(Expression<Func<A, T>> func)
        {
            var h = new ConstructorExpressionHandler<T>();
            h.Process(func);
            if (!h.IsValid) throw new InvalidOperationException("The constructor [" + func + "] is not valid for DI.");

            var result = new Arguments<A, T>(m_Owner, h.Arguments);
            return result;
        }
        public Arguments<A, B, T> Constructor<A, B>(Expression<Func<A, B, T>> func)
        {
            var h = new ConstructorExpressionHandler<T>();
            h.Process(func);
            if (!h.IsValid) throw new InvalidOperationException("The constructor [" + func + "] is not valid for DI.");

            var result = new Arguments<A, B, T>(m_Owner, h.Arguments);
            return result;
        }
        public Arguments<A, B, C, T> Constructor<A, B, C>(Expression<Func<A, B, C, T>> func)
        {
            var h = new ConstructorExpressionHandler<T>();
            h.Process(func);
            if (!h.IsValid) throw new InvalidOperationException("The constructor [" + func + "] is not valid for DI.");

            var result = new Arguments<A, B, C, T>(m_Owner, h.Arguments);
            return result;
        }
        public Arguments<A, B, C, D, T> Constructor<A, B, C, D>(Expression<Func<A, B, C, D, T>> func)
        {
            var h = new ConstructorExpressionHandler<T>();
            h.Process(func);
            if (!h.IsValid) throw new InvalidOperationException("The constructor [" + func + "] is not valid for DI.");

            var result = new Arguments<A, B, C, D, T>(m_Owner, h.Arguments);
            return result;
        }
        public Arguments<A, B, C, D, E, T> Constructor<A, B, C, D, E>(Expression<Func<A, B, C, D, E, T>> func)
        {
            var h = new ConstructorExpressionHandler<T>();
            h.Process(func);
            if (!h.IsValid) throw new InvalidOperationException("The constructor [" + func + "] is not valid for DI.");

            var result = new Arguments<A, B, C, D, E, T>(m_Owner, h.Arguments);
            return result;
        }

        //instance factory
        private Arg[] SetInstanceFactoryMethodInternalCommon<TSource>(LambdaExpression method, Func<string> referenceNameFunc, bool strict, params Type[] argumentTypes)
        {
            var h = new MethodExpressionHandler<TSource>();
            h.Process(method, argumentTypes);
            if (!h.IsValid) throw new InvalidOperationException("The method [" + method + "] is not a valid instance-factory-method.");
            if (h.IsStatic) throw new InvalidOperationException("The method [" + method + "] is not a valid instance-factory-method. Static methods are not allowed.");
            //if ((strict) && (!typeof(T).IsAssignableFrom(h.ReturnType))) throw new InvalidOperationException("The method [" + method + "] is not a valid instance-factory-method. It does not return the correct type");

            m_Owner.SetInstanceFactoryDetails(h.MethodName, referenceNameFunc);
            return h.Arguments;
        }
        private Deployment<T> SetInstanceFactoryMethodInternal<TSource>(LambdaExpression method, Func<string> referenceNameFunc, bool strict, params Type[] argumentTypes)
        {
            var args = SetInstanceFactoryMethodInternalCommon<TSource>(method, referenceNameFunc, strict, argumentTypes);
            return m_Owner;
        }

        public Deployment<T> InstanceFactoryMethod<TSource>(Expression<Func<TSource, T>> method, string referenceName)
        {
            if (referenceName == null) throw new ArgumentNullException("referenceName");
            return SetInstanceFactoryMethodInternal<TSource>(method, () => referenceName, true);
        }
        public Arguments<A, T> InstanceFactoryMethod<TSource, A>(Expression<Func<TSource, A, T>> method, string referenceName)
        {
            if (referenceName == null) throw new ArgumentNullException("referenceName");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, () => referenceName, true, typeof(A));

            var result = new Arguments<A, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, T> InstanceFactoryMethod<TSource, A, B>(Expression<Func<TSource, A, B, T>> method, string referenceName)
        {
            if (referenceName == null) throw new ArgumentNullException("referenceName");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, () => referenceName, true, typeof(A), typeof(B));

            var result = new Arguments<A, B, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, T> InstanceFactoryMethod<TSource, A, B, C>(Expression<Func<TSource, A, B, C, T>> method, string referenceName)
        {
            if (referenceName == null) throw new ArgumentNullException("referenceName");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, () => referenceName, true, typeof(A), typeof(B), typeof(C));

            var result = new Arguments<A, B, C, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, T> InstanceFactoryMethod<TSource, A, B, C, D>(Expression<Func<TSource, A, B, C, D, T>> method, string referenceName)
        {
            if (referenceName == null) throw new ArgumentNullException("referenceName");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, () => referenceName, true, typeof(A), typeof(B), typeof(C), typeof(D));

            var result = new Arguments<A, B, C, D, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, E, T> InstanceFactoryMethod<TSource, A, B, C, D, E>(Expression<Func<TSource, A, B, C, D, E, T>> method, string referenceName)
        {
            if (referenceName == null) throw new ArgumentNullException("referenceName");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, () => referenceName, true, typeof(A), typeof(B), typeof(C), typeof(D), typeof(E));

            var result = new Arguments<A, B, C, D, E, T>(m_Owner, argList);
            return result;
        }

        public Deployment<T> InstanceFactoryMethod<TSource>(Expression<Func<TSource, T>> method, FutureDeployedObject<TSource> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            return SetInstanceFactoryMethodInternal<TSource>(method, reference.GetName, true);
        }
        public Arguments<A, T> InstanceFactoryMethod<TSource, A>(Expression<Func<TSource, A, T>> method, FutureDeployedObject<TSource> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference.GetName, true, typeof(A));

            var result = new Arguments<A, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, T> InstanceFactoryMethod<TSource, A, B>(Expression<Func<TSource, A, B, T>> method, FutureDeployedObject<TSource> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference.GetName, true, typeof(A), typeof(B));

            var result = new Arguments<A, B, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, T> InstanceFactoryMethod<TSource, A, B, C>(Expression<Func<TSource, A, B, C, T>> method, FutureDeployedObject<TSource> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference.GetName, true, typeof(A), typeof(B), typeof(C));

            var result = new Arguments<A, B, C, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, T> InstanceFactoryMethod<TSource, A, B, C, D>(Expression<Func<TSource, A, B, C, D, T>> method, FutureDeployedObject<TSource> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference.GetName, true, typeof(A), typeof(B), typeof(C), typeof(D));

            var result = new Arguments<A, B, C, D, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, E, T> InstanceFactoryMethod<TSource, A, B, C, D, E>(Expression<Func<TSource, A, B, C, D, E, T>> method, FutureDeployedObject<TSource> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference.GetName, true, typeof(A), typeof(B), typeof(C), typeof(D), typeof(E));

            var result = new Arguments<A, B, C, D, E, T>(m_Owner, argList);
            return result;
        }

        public Deployment<T> InstanceFactoryMethod<TSource>(Expression<Func<TSource, T>> method, Func<string> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            return SetInstanceFactoryMethodInternal<TSource>(method, reference, true);
        }
        public Arguments<A, T> InstanceFactoryMethod<TSource, A>(Expression<Func<TSource, A, T>> method, Func<string> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference, true, typeof(A));

            var result = new Arguments<A, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, T> InstanceFactoryMethod<TSource, A, B>(Expression<Func<TSource, A, B, T>> method, Func<string> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference, true, typeof(A), typeof(B));

            var result = new Arguments<A, B, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, T> InstanceFactoryMethod<TSource, A, B, C>(Expression<Func<TSource, A, B, C, T>> method, Func<string> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference, true, typeof(A), typeof(B), typeof(C));

            var result = new Arguments<A, B, C, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, T> InstanceFactoryMethod<TSource, A, B, C, D>(Expression<Func<TSource, A, B, C, D, T>> method, Func<string> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference, true, typeof(A), typeof(B), typeof(C), typeof(D));

            var result = new Arguments<A, B, C, D, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, E, T> InstanceFactoryMethod<TSource, A, B, C, D, E>(Expression<Func<TSource, A, B, C, D, E, T>> method, Func<string> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference, true, typeof(A), typeof(B), typeof(C), typeof(D), typeof(E));

            var result = new Arguments<A, B, C, D, E, T>(m_Owner, argList);
            return result;
        }


        public Deployment<T> UnsafeInstanceFactoryMethod<TSource>(Expression<Func<TSource, object>> method, string referenceName)
        {
            if (referenceName == null) throw new ArgumentNullException("referenceName");
            return SetInstanceFactoryMethodInternal<TSource>(method, () => referenceName, false);
        }
        public Arguments<A, T> UnsafeInstanceFactoryMethod<TSource, A>(Expression<Func<TSource, A, object>> method, string referenceName)
        {
            if (referenceName == null) throw new ArgumentNullException("referenceName");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, () => referenceName, false, typeof(A));

            var result = new Arguments<A, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, T> UnsafeInstanceFactoryMethod<TSource, A, B>(Expression<Func<TSource, A, B, object>> method, string referenceName)
        {
            if (referenceName == null) throw new ArgumentNullException("referenceName");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, () => referenceName, false, typeof(A), typeof(B));

            var result = new Arguments<A, B, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, T> UnsafeInstanceFactoryMethod<TSource, A, B, C>(Expression<Func<TSource, A, B, C, object>> method, string referenceName)
        {
            if (referenceName == null) throw new ArgumentNullException("referenceName");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, () => referenceName, false, typeof(A), typeof(B), typeof(C));

            var result = new Arguments<A, B, C, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, T> UnsafeInstanceFactoryMethod<TSource, A, B, C, D>(Expression<Func<TSource, A, B, C, D, object>> method, string referenceName)
        {
            if (referenceName == null) throw new ArgumentNullException("referenceName");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, () => referenceName, false, typeof(A), typeof(B), typeof(C), typeof(D));

            var result = new Arguments<A, B, C, D, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, E, T> UnsafeInstanceFactoryMethod<TSource, A, B, C, D, E>(Expression<Func<TSource, A, B, C, D, E, object>> method, string referenceName)
        {
            if (referenceName == null) throw new ArgumentNullException("referenceName");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, () => referenceName, false, typeof(A), typeof(B), typeof(C), typeof(D), typeof(E));

            var result = new Arguments<A, B, C, D, E, T>(m_Owner, argList);
            return result;
        }

        public Deployment<T> UnsafeInstanceFactoryMethod<TSource>(Expression<Func<TSource, object>> method, FutureDeployedObject<TSource> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            return SetInstanceFactoryMethodInternal<TSource>(method, reference.GetName, false);
        }
        public Arguments<A, T> UnsafeInstanceFactoryMethod<TSource, A>(Expression<Func<TSource, A, object>> method, FutureDeployedObject<TSource> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference.GetName, false, typeof(A));

            var result = new Arguments<A, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, T> UnsafeInstanceFactoryMethod<TSource, A, B>(Expression<Func<TSource, A, B, object>> method, FutureDeployedObject<TSource> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference.GetName, false, typeof(A), typeof(B));

            var result = new Arguments<A, B, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, T> UnsafeInstanceFactoryMethod<TSource, A, B, C>(Expression<Func<TSource, A, B, C, object>> method, FutureDeployedObject<TSource> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference.GetName, false, typeof(A), typeof(B), typeof(C));

            var result = new Arguments<A, B, C, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, T> UnsafeInstanceFactoryMethod<TSource, A, B, C, D>(Expression<Func<TSource, A, B, C, D, object>> method, FutureDeployedObject<TSource> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference.GetName, false, typeof(A), typeof(B), typeof(C), typeof(D));

            var result = new Arguments<A, B, C, D, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, E, T> UnsafeInstanceFactoryMethod<TSource, A, B, C, D, E>(Expression<Func<TSource, A, B, C, D, E, object>> method, FutureDeployedObject<TSource> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference.GetName, false, typeof(A), typeof(B), typeof(C), typeof(D), typeof(E));

            var result = new Arguments<A, B, C, D, E, T>(m_Owner, argList);
            return result;
        }

        public Deployment<T> UnsafeInstanceFactoryMethod<TSource>(Expression<Func<TSource, object>> method, Func<string> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            return SetInstanceFactoryMethodInternal<TSource>(method, reference, false);
        }
        public Arguments<A, T> UnsafeInstanceFactoryMethod<TSource, A>(Expression<Func<TSource, A, object>> method, Func<string> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference, false, typeof(A));

            var result = new Arguments<A, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, T> UnsafeInstanceFactoryMethod<TSource, A, B>(Expression<Func<TSource, A, B, object>> method, Func<string> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference, false, typeof(A), typeof(B));

            var result = new Arguments<A, B, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, T> UnsafeInstanceFactoryMethod<TSource, A, B, C>(Expression<Func<TSource, A, B, C, object>> method, Func<string> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference, false, typeof(A), typeof(B), typeof(C));

            var result = new Arguments<A, B, C, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, T> UnsafeInstanceFactoryMethod<TSource, A, B, C, D>(Expression<Func<TSource, A, B, C, D, object>> method, Func<string> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference, false, typeof(A), typeof(B), typeof(C), typeof(D));

            var result = new Arguments<A, B, C, D, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, E, T> UnsafeInstanceFactoryMethod<TSource, A, B, C, D, E>(Expression<Func<TSource, A, B, C, D, E, object>> method, Func<string> reference)
        {
            if (reference == null) throw new ArgumentNullException("reference");
            var argList = SetInstanceFactoryMethodInternalCommon<TSource>(method, reference, false, typeof(A), typeof(B), typeof(C), typeof(D), typeof(E));

            var result = new Arguments<A, B, C, D, E, T>(m_Owner, argList);
            return result;
        }

        //static factory
        private Arg[] SetStaticFactoryMethodInternalCommon(LambdaExpression method, bool strict, params Type[] argumentTypes)
        {
            var h = new MethodExpressionHandler<T>();
            h.Process(method, argumentTypes);
            if ((!h.IsValid) || (!h.IsStatic)) throw new InvalidOperationException("The method [" + method + "] is not a valid static-factory-method.");
            //if (!h.IsStatic) throw new InvalidOperationException("The method [" + method + "] is not a valid static-factory-method. Instance methods are not allowed.");            
            //if ((strict) && (!typeof(T).IsAssignableFrom(h.ReturnType))) throw new InvalidOperationException("The method [" + method + "] is not a valid static-factory-method. It does not return the correct type");

            m_Owner.SetStaticFactoryDetails(h.DeclaringType, h.MethodName);
            return h.Arguments;
        }
        private Deployment<T> SetStaticFactoryMethodInternal(LambdaExpression method, bool strict, params Type[] argumentTypes)
        {
            var args = SetStaticFactoryMethodInternalCommon(method, strict, argumentTypes);
            return m_Owner;
        }

        public Deployment<T> StaticFactoryMethod(Expression<Func<T>> method)
        {
            return SetStaticFactoryMethodInternal(method, true);
        }
        public Arguments<A, T> StaticFactoryMethod<A>(Expression<Func<A, T>> method)
        {
            var argList = SetStaticFactoryMethodInternalCommon(method, true, typeof(A));

            var result = new Arguments<A, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, T> StaticFactoryMethod<A, B>(Expression<Func<A, B, T>> method)
        {
            var argList = SetStaticFactoryMethodInternalCommon(method, true, typeof(A), typeof(B));

            var result = new Arguments<A, B, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, T> StaticFactoryMethod<A, B, C>(Expression<Func<A, B, C, T>> method)
        {
            var argList = SetStaticFactoryMethodInternalCommon(method, true, typeof(A), typeof(B), typeof(C));

            var result = new Arguments<A, B, C, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, T> StaticFactoryMethod<A, B, C, D>(Expression<Func<A, B, C, D, T>> method)
        {
            var argList = SetStaticFactoryMethodInternalCommon(method, true, typeof(A), typeof(B), typeof(C), typeof(D));

            var result = new Arguments<A, B, C, D, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, E, T> StaticFactoryMethod<A, B, C, D, E>(Expression<Func<A, B, C, D, E, T>> method)
        {
            var argList = SetStaticFactoryMethodInternalCommon(method, true, typeof(A), typeof(B), typeof(C), typeof(D), typeof(E));

            var result = new Arguments<A, B, C, D, E, T>(m_Owner, argList);
            return result;
        }

        public Deployment<T> UnsafeStaticFactoryMethod(Expression<Func<object>> method)
        {
            return SetStaticFactoryMethodInternal(method, false);
        }
        public Arguments<A, T> UnsafeStaticFactoryMethod<A>(Expression<Func<A, object>> method)
        {
            var argList = SetStaticFactoryMethodInternalCommon(method, false, typeof(A));

            var result = new Arguments<A, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, T> UnsafeStaticFactoryMethod<A, B>(Expression<Func<A, B, object>> method)
        {
            var argList = SetStaticFactoryMethodInternalCommon(method, false, typeof(A), typeof(B));

            var result = new Arguments<A, B, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, T> UnsafeStaticFactoryMethod<A, B, C>(Expression<Func<A, B, C, object>> method)
        {
            var argList = SetStaticFactoryMethodInternalCommon(method, false, typeof(A), typeof(B), typeof(C));

            var result = new Arguments<A, B, C, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, T> UnsafeStaticFactoryMethod<A, B, C, D>(Expression<Func<A, B, C, D, object>> method)
        {
            var argList = SetStaticFactoryMethodInternalCommon(method, false, typeof(A), typeof(B), typeof(C), typeof(D));

            var result = new Arguments<A, B, C, D, T>(m_Owner, argList);
            return result;
        }
        public Arguments<A, B, C, D, E, T> UnsafeStaticFactoryMethod<A, B, C, D, E>(Expression<Func<A, B, C, D, E, object>> method)
        {
            var argList = SetStaticFactoryMethodInternalCommon(method, false, typeof(A), typeof(B), typeof(C), typeof(D), typeof(E));

            var result = new Arguments<A, B, C, D, E, T>(m_Owner, argList);
            return result;
        }
    }
}
